package com.hk.core.data.r2dbc.repository;

import com.hk.core.data.r2dbc.interceptor.R2dbcMultiDatasourceAdvice;
import com.hk.core.data.r2dbc.tenants.ReactiveTenantIdResolver;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.Persistable;
import org.springframework.data.r2dbc.core.R2dbcEntityOperations;
import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy;
import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactoryBean;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor;
import org.springframework.r2dbc.core.DatabaseClient;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author Kevin
 */
public class BaseR2dbcRepositoryFactoryBean<T extends BaseR2dbcRepository<S, ID>, S extends Persistable<ID>,
        ID extends Serializable>
        extends R2dbcRepositoryFactoryBean<T, S, ID> {

    private List<ReactiveTenantIdResolver> resolvers;

    public BaseR2dbcRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
        super(repositoryInterface);
    }

    @Override
    protected RepositoryFactorySupport getFactoryInstance(DatabaseClient client,
                                                          ReactiveDataAccessStrategy dataAccessStrategy) {
        var repositoryFactory = new BaseR2dbcRepositoryFactory(client, dataAccessStrategy);
        repositoryFactory.addRepositoryProxyPostProcessor(new TenantRepositoryProxyPostProcessor());
        return repositoryFactory;
    }

    @Override
    protected RepositoryFactorySupport getFactoryInstance(R2dbcEntityOperations operations) {
        var repositoryFactory = new BaseR2dbcRepositoryFactory(operations);
        repositoryFactory.addRepositoryProxyPostProcessor(new TenantRepositoryProxyPostProcessor());
        return repositoryFactory;
    }

    //可以在spring中定义  ReactiveTenantIdResolver 这些bean
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        super.setApplicationContext(applicationContext);
        Map<String, ReactiveTenantIdResolver> idResolverMap = applicationContext.getBeansOfType(ReactiveTenantIdResolver.class);
        List<ReactiveTenantIdResolver> resolverList = new ArrayList<>(idResolverMap.size());
        resolverList.addAll(idResolverMap.values());
        resolverList.add(ReactiveTenantIdResolver.fixed()); //添加一个默认的
        this.resolvers = Collections.unmodifiableList(resolverList);
    }

    /**
     * 在这里添加切面
     */
    private class TenantRepositoryProxyPostProcessor implements RepositoryProxyPostProcessor {

        @Override
        public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) {
            factory.addAdvice(new R2dbcMultiDatasourceAdvice(resolvers, repositoryInformation.getRepositoryInterface()));
        }
    }
}
